#include "lm_win.h"
#include "../common/lm_log.h"
#include "../common/lm_mem.h"

WINDOW* lm_win_new(WINDOW *parent, int32_t pos_x, int32_t pos_y, int32_t width, int32_t height)
{
    WINDOW* win = NULL;

    if(parent == NULL) {
        win = newwin(height, width, pos_y, pos_x);
        if(win == NULL) {
            LM_LOG_ERROR("The console size is too small");
            return NULL;
        }
    }
    else {
        win = derwin(parent, height, width, pos_y, pos_x);
        if(win == NULL) {
            LM_LOG_ERROR("The console size is too small");
            return NULL;
        }
    }
    return win;
}

void lm_win_destory(WINDOW* win)
{
    delwin(win);
}

int lm_win_set_color(WINDOW *win, lm_color_t color)
{
    if(color.pair != 0) {
        wbkgd(win, COLOR_PAIR(color.pair));
        return color.pair;
    }
    else {
        if(color.rgb_fg_index!=0 && color.rgb_bg_index!=0) {
            int pair = lm_init_pair(color.rgb_fg_index, color.rgb_bg_index);
            wbkgd(win, COLOR_PAIR(pair));
            return pair;
        }
    }
    return LM_ERR;
}


void lm_win_set_pos(lm_win_t *win, int32_t x, int32_t y)
{
    win->pos_x = x;
    win->pos_y = y;
}

int lm_win_get_color(lm_win_t *win)
{
    return win->color.pair;
}


void lm_win_set_size(lm_win_t *win, int32_t width, int32_t height)
{
    win->width = width;
    win->height = height;
}

void lm_win_set_text(lm_win_t *win, const char* text)
{
    if(win->body) {
        werase(win->body);
        mvwaddstr(win->body, 0, 0, text);
        wrefresh(win->body);
    }
}

void lm_win_set_pos_text(lm_win_t *win, int32_t x, int32_t y, const char* text, int color)
{
    if(win->body) {
        wattrset(win->body, COLOR_PAIR(color));
        mvwaddstr(win->body, y, x, text);
        wrefresh(win->body);
    }
}

void lm_win_set_pos_text_no_refresh(lm_win_t *win, int32_t x, int32_t y, const char* text, int color)
{
    if(win->body) {
        wattrset(win->body, COLOR_PAIR(color));
        if(text) {
            mvwaddstr(win->body, y, x, text);
        }
        else {
            mvwaddstr(win->body, y, x, "");
        }
    }
}

void lm_win_clear_text(lm_win_t *win)
{
    werase(win->body);
    wrefresh(win->body);
}

void lm_win_scrol_up(lm_win_t *win)
{
    scrollok(win->body, true);
    wscrl(win->body, 1);
    wrefresh(win->body);
    scrollok(win->body, false);
}

void lm_win_scrol_down(lm_win_t *win)
{
    scrollok(win->body, true);
    wscrl(win->body, -1);
    wrefresh(win->body);
    scrollok(win->body, false);
}

void lm_win_update(lm_win_t* win)
{
    wrefresh(win->body);
    show_panel(win->panel);
    top_panel(win->panel);
    update_panels();
    doupdate();
}


void lm_win_refresh(lm_win_t* win)
{
    wrefresh(win->body);
}

int lm_win_get_width(lm_win_t* win)
{
    return win->width;
}

int lm_win_get_height(lm_win_t* win)
{
    return win->height;
}

lm_win_t* lm_win_create(lm_win_t *parent, int32_t pos_x, int32_t pos_y, int32_t width, int32_t height, lm_color_t color)
{
    WINDOW *pad = NULL;
    lm_win_t *new_win = lm_malloc(sizeof(lm_win_t));
    if(new_win == NULL) {
        LM_LOG_ERROR("The window alloc failed");
        return NULL;
    }

    if(parent == NULL) {
        pad = lm_win_new(NULL, pos_x, pos_y, width, height);
    }
    else {
        pad = lm_win_new(parent->body, pos_x, pos_y, width, height);
    }

    if(pad == NULL) {
        LM_LOG_ERROR("The window new failed");
        lm_free(new_win);
        return NULL;
    }

    new_win->box = NULL;

    new_win->panel = new_panel(pad);
    if(new_win->panel == NULL) {
        LM_LOG_ERROR("The window alloc panel failed");
        lm_win_destory(pad);
        lm_free(new_win);
        return NULL;
    }

    new_win->body = derwin(pad, getmaxy(pad), getmaxx(pad), 0, 0);
    if (new_win->body == NULL) {
        LM_LOG_ERROR("The console size is too small");
        del_panel(new_win->panel);
        lm_win_destory(pad);
        lm_free(new_win);
        return NULL;
    }
    //erase the new window
    werase(new_win->body);

    lm_win_set_pos(new_win, pos_x, pos_y);
    lm_win_set_size(new_win, width, height);

    new_win->color = color;
    new_win->color.pair = lm_win_set_color(new_win->body, color);

    lm_win_update(new_win);

    return new_win;
}


lm_win_t* lm_edge_win_create(lm_win_t *parent, int32_t pos_x, int32_t pos_y, int32_t width, int32_t height, lm_color_t color)
{
    WINDOW *pad = NULL;
    lm_win_t *new_win = lm_malloc(sizeof(lm_win_t));
    if(new_win == NULL) {
        LM_LOG_ERROR("The window alloc failed");
        return NULL;
    }

    if(parent == NULL) {
        pad = lm_win_new(NULL, pos_x, pos_y, width, height);
    }
    else {
        pad = lm_win_new(parent->body, pos_x, pos_y, width, height);
    }

    if(pad == NULL) {
        LM_LOG_ERROR("The window new failed");
        lm_free(new_win);
        return NULL;
    }

    new_win->panel = new_panel(pad);
    if(new_win->panel == NULL) {
        LM_LOG_ERROR("The window alloc panel failed");
        lm_win_destory(pad);
        lm_free(new_win);
        return NULL;
    }

    new_win->box = derwin(pad, getmaxy(pad), getmaxx(pad), 0, 0);
    if(new_win->box == NULL) {
        LM_LOG_ERROR("The console size is too small");
        del_panel(new_win->panel);
        delwin(pad);
        lm_free(new_win);
        return NULL;
    }

    lm_win_set_color(new_win->box, color);
    //erase the box window
    werase(new_win->box);
    box(new_win->box, ACS_VLINE, ACS_HLINE);

    new_win->body = derwin(new_win->box, getmaxy(new_win->box) - 2, getmaxx(new_win->box) - 2, 1, 1);
    if (new_win->body == NULL) {
        LM_LOG_ERROR("The window set subwin failed");
        del_panel(new_win->panel);
        lm_win_destory(pad);
        lm_free(new_win);
        return NULL;
    }
    //erase the new window
    werase(new_win->body);

    lm_win_set_pos(new_win, pos_x, pos_y);
    lm_win_set_size(new_win, width, height);

    new_win->color = color;
    new_win->color.pair = lm_win_set_color(new_win->body, color);

    lm_win_update(new_win);

    return new_win;
}


void lm_win_delete(lm_win_t *win)
{
    WINDOW *window = win->panel->win;
    WINDOW *window_parent = window->_parent;

    if(win->box) {
        delwin(win->box);
    }
    delwin(win->body);
    del_panel(win->panel);
    werase(window);
    delwin(window);
    
    update_panels();
    doupdate();

    lm_free(win);
    if(window_parent) {
        wrefresh(window_parent);
    }
}


lm_title_win_t* lm_title_win_create(lm_win_t *parent, int32_t pos_x, int32_t pos_y, int32_t width, int32_t height, const char* title, lm_color_t color)
{
    WINDOW *pad = NULL;
    lm_title_win_t *title_win = lm_malloc(sizeof(lm_title_win_t));
    if(title_win == NULL) {
        LM_LOG_ERROR("The window alloc failed");
        return NULL;
    }

    lm_win_t *new_win = &title_win->window;

    if(parent == NULL) {
        pad = lm_win_new(NULL, pos_x, pos_y, width, height);
    }
    else {
        pad = lm_win_new(parent->body, pos_x, pos_y, width, height);
    }

    if(pad == NULL) {
        LM_LOG_ERROR("The window new failed");
        lm_free(new_win);
        return NULL;
    }

    new_win->panel = new_panel(pad);
    if(new_win->panel == NULL) {
        LM_LOG_ERROR("The window alloc panel failed");
        lm_win_destory(pad);
        lm_free(new_win);
        return NULL;
    }

    new_win->box = derwin(pad, getmaxy(pad), getmaxx(pad), 0, 0);
    if(new_win->box == NULL) {
        LM_LOG_ERROR("The console size is too small");
        del_panel(new_win->panel);
        delwin(pad);
        lm_free(new_win);
        return NULL;
    }

    lm_win_set_color(new_win->box, color);
    //erase the box window
    werase(new_win->box);
    box(new_win->box, ACS_VLINE, ACS_HLINE);
    mvwhline(new_win->box, 2, 0, ACS_LTEE, 1);
    mvwhline(new_win->box, 2, 1, ACS_HLINE, width - 2);
    mvwhline(new_win->box, 2, width-1, ACS_RTEE, 1);
    wattron(new_win->box, A_BOLD);

    int title_len = strlen(title);
    if(title_len > (width - 2)) {
        title_len = width - 2;
    }

    mvwaddnstr(new_win->box, 1, (width - title_len ) / 2, title, title_len);
    wattron(new_win->box, A_NORMAL);

    new_win->body = derwin(new_win->box, getmaxy(new_win->box) - 4, getmaxx(new_win->box) - 2, 3, 1);
    if (new_win->body == NULL) {
        LM_LOG_ERROR("The console size is too small");
        del_panel(new_win->panel);
        lm_win_destory(pad);
        lm_free(new_win);
        return NULL;
    }

    //erase the new window
    werase(new_win->body);

    lm_win_set_pos(new_win, pos_x, pos_y);
    lm_win_set_size(new_win, width, height);

    new_win->color = color;
    new_win->color.pair = lm_win_set_color(new_win->body, color);

    title_win->title = title;

    lm_win_update(new_win);

    return title_win;
}


void lm_title_win_delete(lm_title_win_t *win)
{
    lm_win_delete(&win->window);
}


void lm_title_win_set_text(lm_title_win_t *win, const char* text)
{
    lm_win_set_text(&win->window, text);
}

void lm_title_win_set_pos_text(lm_title_win_t *win, int32_t x, int32_t y, const char* text, int color)
{
    if(win->window.body) {
        wattrset(win->window.body, COLOR_PAIR(color));
        mvwaddstr(win->window.body, y, x, text);
        wrefresh(win->window.body);
    }
}

void lm_title_win_scrol_up(lm_title_win_t *win)
{
    lm_win_scrol_up(&win->window);
}

void lm_title_win_scrol_down(lm_title_win_t *win)
{
    lm_win_scrol_down(&win->window);
}

void lm_title_win_refresh(lm_title_win_t* win)
{
    lm_win_refresh(&win->window);
}


static void lm_query_win_draw_btn(WINDOW *win, int pos, char *yes_btn, char *no_btn, int color, int toggle_color)
{
    wattrset(win, COLOR_PAIR(color));
    mvwaddstr(win, getmaxy(win) - 2, pos, yes_btn);
    wattrset(win, COLOR_PAIR(toggle_color));
    mvwaddstr(win, getmaxy(win) - 2, pos + strlen(yes_btn) + 8, no_btn);
    wrefresh(win);
}


lm_query_win_t* lm_query_win_create(lm_win_t *parent, int32_t pos_x, int32_t pos_y, int32_t width, int32_t height, const char* title, bool status, lm_color_t color)
{
    WINDOW *pad = NULL;
    char yes_btn[9]="< OK >\0";
    char no_btn[9]="< NO >\0";

    lm_query_win_t *query_win = lm_malloc(sizeof(lm_query_win_t));
    if(query_win == NULL) {
        LM_LOG_ERROR("The window alloc failed");
        return NULL;
    }

    lm_win_t *new_win = &query_win->window;

    if(parent == NULL) {
        pad = lm_win_new(NULL, pos_x, pos_y, width, height);
    }
    else {
        pad = lm_win_new(parent->body, pos_x, pos_y, width, height);
    }

    if(pad == NULL) {
        LM_LOG_ERROR("The window new failed");
        lm_free(new_win);
        return NULL;
    }

    new_win->panel = new_panel(pad);
    if(new_win->panel == NULL) {
        LM_LOG_ERROR("The window alloc panel failed");
        lm_win_destory(pad);
        lm_free(new_win);
        return NULL;
    }

    new_win->box = derwin(pad, getmaxy(pad), getmaxx(pad), 0, 0);
    if(new_win->box == NULL) {
        LM_LOG_ERROR("The console size is too small");
        del_panel(new_win->panel);
        delwin(pad);
        lm_free(new_win);
        return NULL;
    }

    lm_win_set_color(new_win->box, color);
    //erase the box window
    werase(new_win->box);
    box(new_win->box, ACS_VLINE, ACS_HLINE);
    mvwhline(new_win->box, 2, 0, ACS_LTEE, 1);
    mvwhline(new_win->box, 2, 1, ACS_HLINE, width - 2);
    mvwhline(new_win->box, 2, width-1, ACS_RTEE, 1);
    wattron(new_win->box, A_BOLD);

    int title_len = strlen(title);
    if(title_len > (width - 2)) {
        title_len = width - 2;
    }

    mvwaddnstr(new_win->box, 1, (width - title_len ) / 2, title, title_len);
    wattron(new_win->box, A_NORMAL);

    new_win->body = derwin(new_win->box, getmaxy(new_win->box) - 6, getmaxx(new_win->box) - 2, 3, 1);
    if (new_win->body == NULL) {
        LM_LOG_ERROR("The console size is too small");
        del_panel(new_win->panel);
        lm_win_destory(pad);
        lm_free(new_win);
        return NULL;
    }

    //erase the new window
    werase(new_win->body);

    lm_win_set_pos(new_win, pos_x, pos_y);
    lm_win_set_size(new_win, width, height);
    query_win->title = title;

    new_win->color = color;
    new_win->color.pair = lm_win_set_color(new_win->body, color);

    int pos_btn = (getmaxx(new_win->box) - strlen(yes_btn) - strlen(no_btn) - 8 )/2;
    
    query_win->status = status;
    if(status) {
        lm_query_win_draw_btn(new_win->box, pos_btn, yes_btn, no_btn, lm_color_swap(new_win->color), new_win->color.pair);
    }
    else {
        lm_query_win_draw_btn(new_win->box, pos_btn, yes_btn, no_btn, new_win->color.pair, lm_color_swap(new_win->color));
    }

    lm_win_update(new_win);

    return query_win;
}


void lm_query_win_delete(lm_query_win_t *win)
{
    lm_win_delete(&win->window);
}


void lm_query_win_set_status(lm_query_win_t *win, bool status)
{
    lm_win_t *_win = &win->window;
    win->status = status;

    char yes_btn[9]="< OK >\0";
    char no_btn[9]="< NO >\0";
    int pos_btn = (getmaxx(_win->box) - strlen(yes_btn) - strlen(no_btn) - 8 )/2;

    if(status) {
        lm_query_win_draw_btn(_win->box, pos_btn, yes_btn, no_btn, lm_color_swap(_win->color), _win->color.pair);
    }
    else {
        lm_query_win_draw_btn(_win->box, pos_btn, yes_btn, no_btn, _win->color.pair, lm_color_swap(_win->color));
    }

    wrefresh(_win->box);
}

void lm_query_win_set_text(lm_query_win_t *win, const char* text)
{
    lm_win_set_text(&win->window, text);
}

void lm_query_win_scrol_up(lm_query_win_t *win)
{
    lm_win_scrol_up(&win->window);
}

void lm_query_win_scrol_down(lm_query_win_t *win)
{
    lm_win_scrol_down(&win->window);
}

void lm_query_win_refresh(lm_query_win_t* win)
{
    lm_win_refresh(&win->window);
}

